﻿using ExcelConfig;
using filecopy.io.Container;
using filecopy.io.Item;
using SanlieHash.MessageDigest;
using SanlieHash.SecureHash;
using SMBLibrary;
using System;

namespace filecopy.io.Path
{
    public class SmbPath : IFileCopyPath
    {
        public static int WriteBufferSize = 1024 * 64; //写入缓存大小
        internal SmbContainer container { get; set; }
        public SmbPath(IContainer container)
        {
            if (container is SmbContainer smbc) this.container = smbc;
            else throw new Exception("容器不匹配，当前填入非smb容器。");
        }
        public string Path => container.NowPath;

        public long Put(IFileCopyItem item)
        {
            long totalsize = 0;
            var fs = container.smb.TreeConnect(container.sharename, out var status);
            var retrytimes = AppConfig.Number("重试次数");
            var md5 = new MD5();
            var sha3 = new SHA3_512();
            md5.New();
            sha3.New();
            if (status == NTStatus.STATUS_SUCCESS)
            {
                object fileHandle;
                FileStatus fileStatus;
                var smb_filepath = $"{container.nowpath.Replace("/", "\\")}\\{item.FileName}";
                status = fs.CreateFile(out fileHandle, out fileStatus, smb_filepath, AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, SMBLibrary.FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_CREATE, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
                var error_times = 0;
                if (status == NTStatus.STATUS_SUCCESS)
                {
                    int numberOfBytesWritten;
                    foreach (var i in item.GetStream(WriteBufferSize))
                    {
                        numberOfBytesWritten = 0;
                        while (error_times < retrytimes + 1)
                        {
                            status = fs.WriteFile(out numberOfBytesWritten, fileHandle, totalsize, item.Buffer);
                            md5.Update(item.Buffer);
                            sha3.Update(item.Buffer);
                            if (status != NTStatus.STATUS_SUCCESS)
                            {
                                error_times++;
                                if (error_times < retrytimes) continue;
                                throw new Exception($"文件写入过程出错。文件： {item.FileName} {status}  in {totalsize}");
                            }
                            else { error_times = 0;  break; }
                        }
                        totalsize += numberOfBytesWritten;
                    }
                    status = fs.FlushFileBuffers(fileHandle);
                    if (status != NTStatus.STATUS_SUCCESS) throw new Exception($"文件推入过程出错。文件： {item.FileName} {status}");
                    status = fs.CloseFile(fileHandle);
                    if (status != NTStatus.STATUS_SUCCESS) throw new Exception($"文件关闭过程出错。文件： {item.FileName} {status}");
                }
                else throw new Exception($"创建文件过程出错，无法执行文件写入操作。 {status}");

                fs.Disconnect();
            }
            else throw new Exception($"访问出错， 访问目标{container.sharename} {status}");

            Console.WriteLine($"MD5: {md5.Make()}");
            Console.WriteLine($"SHA3(512): {sha3.Make()}");
            return totalsize;
        }
    }
}
